﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Reflection;
using Anno.Const.Attribute;
using System.Collections.Generic;
using Anno.Rpc.Storage;

namespace Anno.Wcf.Server
{
    using Anno.Const;
    using Anno.Log;
    using Autofac;
    using System.IO;
    using System.Threading;

    public static partial class Bootstrap
    {
        /// <summary>
        /// 是否为重新注册
        /// </summary>
        private static bool regRegister = false;
        /// <summary>
        /// 启动 server
        /// </summary>
        /// <param name="args"></param> 
        /// <param name="diAction"></param>
        /// <param name="iocType">依赖注入类型</param>
        public static void StartUp(string[] args, Action diAction, Action startUpCallBack = null, Loader.IocType iocType = Loader.IocType.Autofac)
        {
            var reStar = false;
        reStart:
            try
            {
                if (args != null && args.Contains("--reg"))
                {
                    regRegister = true;
                }
                Enter(args, diAction, reStar, iocType);
                if (regRegister)
                {
                    Log.WriteLine("重新注册完成，3秒后窗口自动关闭");
#if NET40
                    TaskEx.Delay(3000).Wait();
#else
                    Task.Delay(3000).Wait();
#endif
                    return;
                }
                try
                {
                    startUpCallBack?.Invoke();
                }
                catch (Exception ex)
                {
                    Log.WriteLineAlignNoDate(ex.Message);
                }
                AppDomain.CurrentDomain.ProcessExit += (s, e) =>
                {
                    if (Server.State)
                    {
                        Log.WriteLine($"{Const.SettingService.AppName} Service is being stopped·····", ConsoleColor.DarkGreen);
                        Server.Stop();
                        Log.WriteLine($"{Const.SettingService.AppName} The service has stopped!", ConsoleColor.DarkGreen);
                    }
                };
                //阻止daemon进程退出
                (new AutoResetEvent(false)).WaitOne();
            }
            catch (Exception e)
            {
                Log.Error(e);
                if (e is Thrift.TException)
                {
                    reStar = true;
                }
                else
                {
                    throw;
                }
            }
            //服务因为传输协议异常自动退出，需要重启启动。如果是配置错误弹出配置错误信息
            goto reStart;
        }
        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="args"></param>
        /// <param name="diAction"></param>
        /// <param name="reStart">异常之中回复启动，true。正常启动，false</param>
        static void Enter(string[] args, Action diAction, bool reStart, Loader.IocType iocType)
        {
            Const.Assemblys.AddOtherPlugsAssembly.Add(AddOtherPlugsAssembly);
            Const.Assemblys.RegisterOtherAssembly.Add(RegisterOtherAssembly);
            Const.Assemblys.BuilderOtherRouterInfo.Add(BuilderOtherRouterInfo);

            if ((!reStart) || regRegister)
            {
                EngineData.AnnoBootstrap.Bootstrap(diAction, iocType);
            }
            #region 设置监听端口（可以通过参数 设置。没有取配置文件）

            int.TryParse(ArgsValue.GetValueByName("-p", args), out int port);
            if (port > 0)
            {
                Const.SettingService.Local.Port = port;
            }
            int.TryParse(ArgsValue.GetValueByName("-xt", args), out int maxThreads);
            if (maxThreads > 0)
            {
                Const.SettingService.MaxThreads = maxThreads;
            }
            long.TryParse(ArgsValue.GetValueByName("-t", args), out long timeout);
            if (timeout > 0)
            {
                Const.SettingService.TimeOut = timeout;
            }
            int.TryParse(ArgsValue.GetValueByName("-w", args), out int weight);
            if (weight > 0)
            {
                Const.SettingService.Weight = weight;
            }

            var host = ArgsValue.GetValueByName("-h", args);
            if (host != null)
            {
                System.Net.IPAddress.TryParse(host, out System.Net.IPAddress ipAddress);
                if (ipAddress != null)
                {
                    Const.SettingService.Local.IpAddress = host;
                }
                else
                {
                    Log.WriteLine("-h 参数错误!", ConsoleColor.DarkYellow);
                }
            }
            var traceOnOffStr = ArgsValue.GetValueByName("-tr", args);
            if (!string.IsNullOrWhiteSpace(traceOnOffStr))
            {
                bool.TryParse(traceOnOffStr, out bool traceOnOff);
                Const.SettingService.TraceOnOff = traceOnOff;
            }
            #endregion
            if ((!Server.State) && (!regRegister))
            {
                Server.Start();
            }
            Log.WriteLine($"节点【{Const.SettingService.AppName}】(端口：{Const.SettingService.Local.Port})已启动", ConsoleColor.DarkGreen);
            foreach (var f in Const.SettingService.FuncName.Split(','))
            {
                Log.WriteLine($"{f}", ConsoleColor.DarkGreen);
            }
            Log.WriteLine($"{"权重:" + Const.SettingService.Weight}", ConsoleColor.DarkGreen);
            Log.WriteLineNoDate("-----------------------------------------------------------------------------");
            Const.SettingService.Ts.ForEach(t => { new Rpc.Client.Register().ToCenter(t, 60); });
            /*
             * 1、 Const.SettingService.Local 在AnnoService(服务提供方)中 作为 本机信息
             * 2、Const.SettingService.Local 在客户端 作为 负载均衡地址信息(AnnoCenter)
             * 3、此处为了让AnnoService 可以调用外部服务 Local使用完毕后更改为 AnnoCenter 地址
             */
            Const.Target target = Const.SettingService.Ts?.First();
            Rpc.Client.DefaultConfigManager.SetDefaultConfiguration(Const.SettingService.AppName, target.IpAddress, target.Port, Const.SettingService.TraceOnOff);
        }

        /// <summary>
        ///服务启动后将服务Api文档写入注册中心
        ///
        ///增加自己的服务的时候只用复制下面的代码就可以不用做修改
        /// </summary>
        public static void ApiDoc()
        {
            List<AnnoData> routings = new List<AnnoData>();
            foreach (var item in EngineData.Routing.Routing.Router)
            {
                if (item.Value.RoutMethod.Name == "get_ActionResult")
                {
                    continue;
                }
                var parameters = item.Value.RoutMethod.GetParameters().ToList().Select(it =>
                {
                    var parameter = new ParametersValue
                    { Name = it.Name, Position = it.Position, ParameterType = it.ParameterType.FullName };
                    var pa = it.GetCustomAttributes<AnnoInfoAttribute>().ToList();
                    if (pa.Any())
                    {
                        parameter.Desc = pa.First().Desc;
                    }
                    return parameter;
                }).ToList();
                string methodDesc = String.Empty;
                var mAnnoInfoAttributes = item.Value.RoutMethod.GetCustomAttributes<AnnoInfoAttribute>().ToList();
                if (mAnnoInfoAttributes.Count > 0)
                {
                    methodDesc = mAnnoInfoAttributes.First().Desc;
                }
                routings.Add(new AnnoData()
                {
                    App = Anno.Const.SettingService.AppName,
                    Id = $"{Anno.Const.SettingService.AppName}:{item.Key}",
                    Value = Newtonsoft.Json.JsonConvert.SerializeObject(new DataValue { Desc = methodDesc, Name = item.Value.RoutMethod.Name, Parameters = parameters })
                });
            }
            Dictionary<string, string> input = new Dictionary<string, string>();
            input[StorageCommand.COMMAND] = StorageCommand.APIDOCCOMMAND;
            input.Add(CONST.Opt, CONST.DeleteByApp);
            input.Add(CONST.App, Anno.Const.SettingService.AppName);
            var del = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
            if (del.Status == false)
            {
                Log.Error(del);
            }
            input.Clear();
            input[StorageCommand.COMMAND] = StorageCommand.APIDOCCOMMAND;
            input.Add(CONST.Opt, CONST.UpsertBatch);
            input.Add(CONST.Data, Newtonsoft.Json.JsonConvert.SerializeObject(routings));
            var rlt = Newtonsoft.Json.JsonConvert.DeserializeObject<AnnoDataResult>(StorageEngine.Invoke(input));
            if (rlt.Status == false)
            {
                Log.Error(rlt);
            }
        }

        /// <summary>
        /// 添加扩展Assembly
        /// </summary>
        static void AddOtherPlugsAssembly()
        {
            #region Wcf Packages 目录 插件
#if NETFRAMEWORK
            var wcfBasePath = Path.Combine(Directory.GetCurrentDirectory(), "WcfPackages");
            Console.WriteLine($"wcfBasePath：{wcfBasePath}");
            if (Directory.Exists(wcfBasePath))
            {
                foreach (DirectoryInfo plugInfo in new DirectoryInfo(wcfBasePath).GetDirectories())
                {
                    try
                    {
                        var plugName = plugInfo.Name; //$"Anno.Plugs.SerialRule";
                        var plugNameService = $"{plugName}";
                        var plugsPath = Path.Combine(wcfBasePath, plugName, $"{plugNameService}.dll");
                        Console.WriteLine($"WcfPlugsPath：{plugsPath}");
                        if (File.Exists(plugsPath))
                        {
                            var assembly = Assembly.UnsafeLoadFrom(plugsPath); //装载组件
                            if (!Const.Assemblys.Dic.ContainsKey(plugNameService))
                            {
                                Const.Assemblys.Dic.Add($"{plugNameService}", assembly);
                                if (!string.IsNullOrEmpty(Const.SettingService.FuncName))
                                {
                                    Const.SettingService.FuncName += ",";
                                }
                                Const.SettingService.FuncName += plugNameService;
                                Console.WriteLine($"FuncName：{Const.SettingService.FuncName}");
                            }
                            if (Const.AppSettings.IocDll.All(plug => plug != plugNameService))
                            {
                                Const.AppSettings.IocDll.Add(plugNameService);
                                Console.WriteLine($"AppSettings.IocDll.Count：{Const.AppSettings.IocDll.Count}");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"插件【{plugInfo.Name}】加载出错！");
                        Console.WriteLine($"错误信息：");
                        Console.WriteLine(ex.Message);
                    }
                }
            }
#endif
            #endregion
        }
        /// <summary>
        /// 注册WCF服务
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assembly"></param>
        /// <param name="lifetime"></param>
        /// <param name="t"></param>
        static void RegisterOtherAssembly(ContainerBuilder builder, Assembly assembly, string lifetime, Type t)
        {
            //注册WCF服务
            if (t.GetCustomAttribute<System.ServiceModel.ServiceContractAttribute>() != null)
            {
                if (t.IsGenericType)
                {
                    switch (lifetime)
                    {
                        case "Singleton":
                            builder.RegisterGeneric(t).SingleInstance();
                            break;
                        case "Scoped":
                            builder.RegisterGeneric(t).InstancePerLifetimeScope();
                            break;
                        default:
                            builder.RegisterGeneric(t);
                            break;
                    }
                }
                else
                {
                    switch (lifetime)
                    {
                        case "Singleton":
                            builder.RegisterType(t).SingleInstance();
                            break;
                        case "Scoped":
                            builder.RegisterType(t).InstancePerLifetimeScope();
                            break;
                        default:
                            builder.RegisterType(t);
                            break;
                    }
                }
            }
        }
        /// <summary>
        /// 构建路由信息
        /// </summary>
        /// <param name="svc"></param>
        static void BuilderOtherRouterInfo(Assembly svc,Type baseModuleType)
        {
            svc.GetTypes().Where(x => x.GetInterfaces()?.Length > 0
                 && x.GetInterfaces().Where(s => s.GetCustomAttribute<System.ServiceModel.ServiceContractAttribute>() != null).Any()
                 && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsInterface
                 && !baseModuleType.IsAssignableFrom(x))?.ToList().ForEach(t =>
                 {
                     var methods = t.GetMethods().Where(m => !m.DeclaringType.Equals(typeof(object)) && m.IsPublic);
                     foreach (var method in methods)
                     {
                         var routInfo = new EngineData.Routing.RoutInfo()
                         {
                             RoutMethod = method,
                             RoutModuleType = t
                         };
                        #region Authorization Filters
                        // /*
                        //* 全局过滤器
                        //*/
                        // routInfo.AuthorizationFilters.AddRange(Routing.Routing.GlobalAuthorizationFilters);
                        // /*
                        // * 模块过滤器
                        // */
                        // routInfo.AuthorizationFilters.AddRange(t.GetAnnoCustomAttributes<IAuthorizationFilter>());
                        // /*
                        // * 方法过滤器
                        // */
                        // routInfo.AuthorizationFilters.AddRange(method.GetAnnoCustomAttributes<IAuthorizationFilter>());
                        #endregion
                        #region Action Filters
                        ///*
                        //* 全局过滤器
                        //*/
                        //routInfo.ActionFilters.AddRange(Routing.Routing.GlobalActionFilters);
                        ///*
                        //* 模块过滤器
                        //*/
                        //routInfo.ActionFilters.AddRange(routInfo.RoutModuleType.GetAnnoCustomAttributes<IActionFilter>());
                        ///*
                        //* 方法过滤器
                        //*/
                        //routInfo.ActionFilters.AddRange(routInfo.RoutMethod.GetAnnoCustomAttributes<IActionFilter>());

                        #endregion
                        #region Exception Filters
                        // /*
                        //* 方法过滤器
                        //*/
                        // routInfo.ExceptionFilters.AddRange(routInfo.RoutMethod.GetAnnoCustomAttributes<IExceptionFilter>());
                        // /*
                        // * 模块过滤器
                        // */
                        // routInfo.ExceptionFilters.AddRange(routInfo.RoutModuleType.GetAnnoCustomAttributes<IExceptionFilter>());
                        // /*
                        //  * 全局过滤器
                        //  */
                        // routInfo.ExceptionFilters.AddRange(Routing.Routing.GlobalExceptionFilters);
                        #endregion
                        #region CacheMiddleware 
                        ///*
                        // * 全局Cache
                        //*/
                        //routInfo.CacheMiddleware.AddRange(Routing.Routing.GlobalCacheMiddleware);
                        ///*
                        // * 模块Cache
                        //*/
                        //routInfo.CacheMiddleware.AddRange(routInfo.RoutModuleType.GetCustomAttributes<Cache.CacheMiddlewareAttribute>());
                        ///*
                        // * 方法Cache
                        //*/
                        //routInfo.CacheMiddleware.AddRange(routInfo.RoutMethod.GetCustomAttributes<Cache.CacheMiddlewareAttribute>());
                        #endregion
                         var key = $"{t.FullName}/{method.Name}";
                         if (EngineData.Routing.Routing.Router.ContainsKey(key))
                         {
                             EngineData.Routing.Routing.Router[key] = routInfo;
                         }
                         else
                         {
                             EngineData.Routing.Routing.Router.TryAdd(key, routInfo);
                         }
                     }

                     //处理 FuncPath
                     t.SetFuncPath();
                 });
        }
    }
}
